package com.nulldev.util.web.HttpServer3.extensions.nCaptcha;

import com.nulldev.util.JVM.Arguments;
import com.nulldev.util.JVM.JVM;
import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.data.Variables;
import com.nulldev.util.manage.Version;
import com.nulldev.util.manage.nullUtil;
import com.nulldev.util.web.HttpServer3.HttpServer;
import com.nulldev.util.web.HttpServer3.HttpServer3;
import com.nulldev.util.web.HttpServer3.HttpServer3.nCaptchaEnforcementMethod;
import com.nulldev.util.web.HttpServer3.Response;
import com.nulldev.util.web.HttpServer3.SSLBehaviour;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.backend.Captcha;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.backend.CaptchaJSONPage;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.backend.CaptchaPage;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.backend.CheckCaptcha;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.backend.RemoveCaptchaState;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.backend.RequestCaptcha;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.backend.ValidUID;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.backend.user.User;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.backend.user.UserInfoType;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.advanced.ImageTextCaptchaV2;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.advanced.ImageTextCaptchaV3;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.advanced.MultiWordCheck;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.auto.AutoPayloadHoneypot;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.auto.AutoPayloadSubmission;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.auto.RequestAutoCaptchaPayload;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.obftext.ImageTextCaptcha;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.obftext.MathCaptcha;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.obftext.TrueFalseStatement;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.shapes.ShapeIdentification;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.v4.proposal_b.TLSCaptchaPage;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.v4.proposal_d.GryoscopeChallengePlaceholderChallenge;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.captchas.v4.proposal_d.GyroscopeChallengeWebSocketPage;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.demo.LegacyCaptchaDemoResource;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.noscript_frontend.ChallengeGeneratorPage;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.noscript_frontend.ChallengeIFramePage;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.noscript_frontend.NoScriptFrontendResource;
import com.nulldev.util.web.HttpServer3.extensions.nCaptcha.resources.nCaptchaResource;
import com.nulldev.util.web.HttpServer3.pages.v3.HttpPage3;
import com.nulldev.util.web.HttpServer3.pages.v3.HttpPage3.CachingMethod;

public class nCaptcha {
	private static final Captcha GRYOSCOPE_CHALLENGE_V4 = new GryoscopeChallengePlaceholderChallenge();

	/* */

	public static final Version VERSION = new Version(3, 3, 0);

	public static final boolean NCAPTCHA_ENABLE_DEBUGGING = Arguments.hasArgument("--nCaptcha.debug", "-nCaptcha.debug");

	public static final Captcha[] CAPTCHAS =
		{ new ImageTextCaptcha(), new ImageTextCaptchaV2(), new ImageTextCaptchaV3(), new ShapeIdentification(), new MathCaptcha(), new TrueFalseStatement(),
				new MultiWordCheck(), };

	public static Captcha randomCaptcha(final User user) {
		if (user.hasInfoObject(UserInfoType.USER_INFO_V4_GRYO_CHALLENGE_SUPPORTED)) {
			return GRYOSCOPE_CHALLENGE_V4;
		} else {
			return ArrayUtils.random(CAPTCHAS);
		}
	}

	public static Captcha randomCaptcha() {
		return ArrayUtils.random(CAPTCHAS);
	}

	public static void loadCaptchaSystem(final HttpServer server) {
		loadCaptchaSystem(server, true);
	}

	public static void loadCaptchaSystem(final HttpServer server, final boolean loadCaptchaPage) {
		Variables.requireNonNull(server, "server");
		/* Required by nCaptcha 4.x */
		server.flags().enable_ws = true;
		if (loadCaptchaPage) {
///			!!! Don't cache as we override requests, breaking caching.
			server.addDynamicAssetBytes("/captcha", nCaptchaResource.class, "captcha.html", CachingMethod.NO_CACHE, true);
			server.addPage(new CaptchaJSONPage());
		}
		server.addPage(new RequestCaptcha());
		server.addPage(new CheckCaptcha());
		server.addPage(new ValidUID());
		if (nullUtil.IS_NON_MAINLINE_BUILD)
			server.addPage(new RemoveCaptchaState());
		server.addPage(new RequestAutoCaptchaPayload());
		server.addPage(new AutoPayloadSubmission());
		server.addPage(new AutoPayloadHoneypot());
		/* v4 */
		server.addPage(new GyroscopeChallengeWebSocketPage());
		/* */
		server.addDynamicAssetBytes("/captcha/blowfish.js", Captcha.class, "blowfish.js", CachingMethod.VERY_LONG_CACHE, true);
		server.addDynamicAssetBytes("/captcha/xxtea.js", Captcha.class, "xxtea.js", CachingMethod.VERY_LONG_CACHE, true);
		server.addDynamicAssetBytes("/captcha/sha256.js", Captcha.class, "sha256.js", CachingMethod.VERY_LONG_CACHE, true);
		server.addDynamicAssetBytes("/captcha/libWeb.js", Captcha.class, "libWeb.js", CachingMethod.VERY_LONG_CACHE, true);
		server.addDynamicAssetBytes("/captcha/datamatrix.js", Captcha.class, "datamatrix.js", CachingMethod.VERY_LONG_CACHE, true);
		server.addDynamicAssetBytes("/captcha/libCaptcha.js", nCaptchaResource.class, "libCaptcha.js", CachingMethod.VERY_LONG_CACHE, true);
		/* NoScript */
		server.addDynamicAssetBytes("/captcha-ns", NoScriptFrontendResource.class, "initial-loader.html", CachingMethod.NO_CACHE, true);
		server.addDynamicAssetBytes("/captcha/challenge-cooldown", NoScriptFrontendResource.class, "challenge-cooldown.html", CachingMethod.NO_CACHE, true);
		server.addDynamicAssetBytes("/captcha/challenge-cooldown-short", NoScriptFrontendResource.class, "challenge-cooldown-short.html",
				CachingMethod.NO_CACHE, true);
		server.addDynamicAssetBytes("/captcha/challenge-passed", NoScriptFrontendResource.class, "challenge-passed.html", CachingMethod.NO_CACHE, true);
		server.addPage(new ChallengeIFramePage());
		server.addPage(new ChallengeGeneratorPage());
	}

	public static void main(String[] args) {
		try {
			final HttpServer3 htps3 = new HttpServer3(9000, false, SSLBehaviour.DISABLED, null);
			htps3.setServerName("HttpServer3: Captcha Demo");
			htps3.setDebugging(true);
			htps3.settings().enableNCaptcha = true;
			htps3.settings().nCaptchaMethod = nCaptchaEnforcementMethod.NO_ENFORCEMENT;
			loadCaptchaSystem(htps3);
			htps3.addPage(new CaptchaPage());
			htps3.addPage(new TLSCaptchaPage());
			htps3.addDynamicAssetBytes("/captcha/captcha_v2", LegacyCaptchaDemoResource.class, "captcha_demo.html", CachingMethod.NO_CACHE, true);
			htps3.addPage(new HttpPage3("/") {

				@Override
				public Response onRequest(final Request request) {
					return new Response(200, createStream("Hello world!"));
				}
			});
			htps3.addDynamicAssetBytes("/libcaptcha-demo", nCaptchaResource.class, "libcaptcha-demo.html", CachingMethod.NO_CACHE, true);
			JVM.println("Pages: ");
			htps3.dumpPages();
		} catch (Exception ex) {
			JVM.errorln(ex);
		}
	}
}
